package com.vinku.agent.transformer;

import com.vinku.agent.inteeceptor.TimeInterceptor;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;

/**
 * @Author Vinku
 * @Description
 */
public class ByteBuddyTransformer  {

    public static void installTransformer(Instrumentation inst) {
        //动态构建操作，根据transformer规则执行拦截操作
        AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {
            @Override
            public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
                                                    // 匹配上的具体的类型描述
                                                    TypeDescription typeDescription,
                                                    ClassLoader classLoader,
                                                    JavaModule javaModule) {
                //构建拦截规则
                return builder
                        //method()指定哪些方法需要被拦截，ElementMatchers.any()表示拦截所有方法
                        .method(ElementMatchers.<MethodDescription>any())
                        //intercept()指定拦截上述方法的拦截器
                        .intercept(MethodDelegation.to(TimeInterceptor.class))
                        .method(ElementMatchers.isToString())
                        .intercept(FixedValue.value("拦截了toString()"));
            }
        };

        //采用Byte Buddy的AgentBuilder结合Java Agent处理程序
        new AgentBuilder
                //采用ByteBuddy作为默认的Agent实例
                .Default()
                //拦截匹配方式：com.vinku.app下所有类
                .type(ElementMatchers.nameStartsWith("com.vinku.app"))
                //拦截到的类由transformer处理
                .transform(transformer)
                //安装到 Instrumentation
                .installOn(inst);
    }


}
